package com.sunhapper.x.spedit.gif.span

import android.R.attr
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Paint.FontMetricsInt
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.style.DynamicDrawableSpan
import android.text.style.ImageSpan
import android.widget.RelativeLayout.ALIGN_TOP
import com.sunhapper.x.spedit.gif.drawable.InvalidateDrawable
import com.sunhapper.x.spedit.gif.drawable.ResizeDrawable


/**
 * 和文字等高的ImageSpan
 * 在选择模式下，光标的index可能在Span对应的文字内部，标记为IntegratedSpan可以防止光标
 * 在内部，在replace其他文字时可以正常删除该span
 */
open class GifImageSpan : ImageSpan, RefreshSpan {
    protected var resized = false
    protected var drawableHeight = 200

    constructor(d: Drawable) : super(d)

    constructor(d: Drawable, verticalAlignment: Int) : super(d, verticalAlignment)

    constructor(d: Drawable, source: String) : super(d, source)

    constructor(d: Drawable, source: String, verticalAlignment: Int) : super(d, source, verticalAlignment)

    constructor(context: Context, uri: Uri) : super(context, uri)

    constructor(context: Context, uri: Uri, verticalAlignment: Int) : super(context, uri, verticalAlignment)
    constructor(context: Context, resourceId: Int) : super(context, resourceId)

    constructor(context: Context, resourceId: Int, verticalAlignment: Int) : super(context, resourceId, verticalAlignment)

    constructor(b: Bitmap) : super(b)

    constructor(b: Bitmap, verticalAlignment: Int) : super(b, verticalAlignment)

    constructor(context: Context, b: Bitmap) : super(context, b)

    constructor(context: Context, b: Bitmap, verticalAlignment: Int) : super(context, b, verticalAlignment)

    fun getResizedDrawable(): Drawable {
        val d = drawable
        if (drawableHeight == 0) {
            return d
        }
        if (d is ResizeDrawable && (d.needResize || !resized)) {
            resizeSpan(d)
        } else if (!resized) {
            resizeSpan(d)
        }
        return d
    }

    private fun resizeSpan(d: Drawable) {
        resized = true
        d.bounds = Rect(0, 0,
                (1f * drawableHeight * d.intrinsicWidth / d.intrinsicHeight).toInt(),
                drawableHeight)
        //d.bounds = Rect(d.bounds.left, d.bounds.top, d.intrinsicWidth, d.intrinsicHeight)
    }

    override fun getInvalidateDrawable(): InvalidateDrawable? {
        val d = getResizedDrawable()
        return if (d is InvalidateDrawable) {
            d
        } else {
            null
        }
    }

    override fun getSize(paint: Paint, text: CharSequence,
                         start: Int, end: Int, fm: FontMetricsInt?): Int {
        val d: Drawable = getResizedDrawable()
        val rect = d.bounds
        if (fm != null) {
            val fmPaint = paint.fontMetrics
            // 顶部 leading
            val topLeading = fmPaint.top - fmPaint.ascent
            // 底部 leading
            val bottomLeading = fmPaint.bottom - fmPaint.descent
            // drawable 的高度
            val drHeight = rect.height()
            when (mVerticalAlignment) {
                DynamicDrawableSpan.ALIGN_CENTER -> {
                    // drawable 的中间与 行中间对齐
                    // 当前行 的高度
                    val fontHeight = fmPaint.descent - fmPaint.ascent
                    // 整行的 y方向上的中间 y 坐标
                    val center = fmPaint.descent - fontHeight / 2

                    // 算出 ascent 和 descent
                    val ascent = center - drHeight / 2
                    val descent = center + drHeight / 2
                    fm.ascent = ascent.toInt()
                    fm.top = (ascent + topLeading).toInt()
                    fm.descent = descent.toInt()
                    fm.bottom = (descent + bottomLeading).toInt()
                }
                DynamicDrawableSpan.ALIGN_BASELINE -> {
                    // drawable 的底部与 baseline 对齐
                    // 所以 ascent 的值就是 负的 drawable 的高度
                    val ascent = -drHeight.toFloat()
                    fm.ascent = -drHeight
                    fm.top = (ascent + topLeading).toInt()
                }
                ALIGN_TOP -> {
                    // drawable 的顶部与 行的顶部 对齐
                    // 算出 descent
                    val descent = drHeight + fmPaint.ascent
                    fm.descent = descent.toInt()
                    fm.bottom = (descent + bottomLeading).toInt()
                }
                DynamicDrawableSpan.ALIGN_BOTTOM -> {

                    // 算出 ascent
                    val ascent = fmPaint.descent - drHeight
                    fm.ascent = ascent.toInt()
                    fm.top = (ascent + topLeading).toInt()
                }
                else -> {
                    val ascent = fmPaint.descent - drHeight
                    fm.ascent = ascent.toInt()
                    fm.top = (ascent + topLeading).toInt()
                }
            }
        }
        return rect.right
    }

    override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int,
                      bottom: Int, paint: Paint) {

        val s = text.toString()
        val subS = s.substring(start, end)
        if (ELLIPSIS_NORMAL[0] == subS[0] || ELLIPSIS_TWO_DOTS[0] == subS[0]) {
            canvas.save()
            canvas.drawText(subS, x, y.toFloat(), paint)
            canvas.restore()
        } else {
            val d = getResizedDrawable()
            val rect = d.bounds
            val transY: Float
            transY = when (mVerticalAlignment) {
                DynamicDrawableSpan.ALIGN_BASELINE -> attr.y - rect.height().toFloat()
                DynamicDrawableSpan.ALIGN_CENTER -> ((bottom - top - rect.height()) / 2 + top).toFloat()
                ALIGN_TOP -> top.toFloat()
                DynamicDrawableSpan.ALIGN_BOTTOM -> (bottom - rect.height()).toFloat()
                else -> (bottom - rect.height()).toFloat()
            }
            canvas.save()
            canvas.translate(x, transY)
            d.draw(canvas)
            canvas.restore()
        }
    }

    companion object {
        private val ELLIPSIS_NORMAL = charArrayOf('\u2026') // this is "..."
        private val ELLIPSIS_TWO_DOTS = charArrayOf('\u2025') // this is ".."
    }

}
